package com.wiscamp.ninechapters.problems.application.services;

import com.wiscamp.ninechapters.common.core.RandomHelper;
import com.wiscamp.ninechapters.problems.application.assemblers.ProblemAssembler;
import com.wiscamp.ninechapters.problems.application.assemblers.TaskAssembler;
import com.wiscamp.ninechapters.problems.application.dto.commands.tasks.AssignProblemSetCommand;
import com.wiscamp.ninechapters.problems.application.dto.commands.tasks.CreateTaskByCollectionCommand;
import com.wiscamp.ninechapters.problems.application.dto.commands.tasks.CreateTaskByKnowledgePointsCommand;
import com.wiscamp.ninechapters.problems.application.dto.commands.tasks.CreateTaskByRuleCommand;
import com.wiscamp.ninechapters.problems.application.dto.vo.problems.ProblemVO;
import com.wiscamp.ninechapters.problems.application.dto.vo.tasks.TaskVO;
import com.wiscamp.ninechapters.problems.domain.gateway.TagGateway;
import com.wiscamp.ninechapters.problems.domain.repositories.ProblemCollectionRepository;
import com.wiscamp.ninechapters.problems.domain.repositories.ProblemSetRepository;
import com.wiscamp.ninechapters.problems.domain.repositories.RegroupRuleRepository;
import com.wiscamp.ninechapters.problems.domain.repositories.TaskRepository;
import com.wiscamp.ninechapters.problems.domain.services.ProblemService;
import com.wiscamp.ninechapters.problems.domain.services.ProblemSetService;
import com.wiscamp.ninechapters.problems.domain.services.RegroupRuleService;
import com.wiscamp.ninechapters.problems.domain.services.TaskService;
import cube.common.core.CollectionUtils;
import cube.ddd.application.BaseAppService;
import cube.ddd.aspect.HandleServiceException;
import cube.ddd.common.query.PagedObjects;
import cube.ddd.common.query.PagedQuery;
import cube.ddd.utils.AppServiceUtils;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects;

@Service
public class TaskAppService extends BaseAppService {
    private final TaskRepository taskRepository;
    private final ProblemSetRepository problemSetRepository;

    private final RegroupRuleRepository regroupRuleRepository;

    private final TaskService taskService;

    private final ProblemService problemService;

    private final ProblemSetService problemSetService;

    private final RegroupRuleService regroupRuleService;

    private final TagGateway tagGateway;

    public TaskAppService(TaskRepository taskRepository, ProblemCollectionRepository problemCollectionRepository, ProblemSetRepository problemSetRepository, RegroupRuleRepository regroupRuleRepository, TaskService taskService, ProblemService problemService, ProblemSetService problemSetService, RegroupRuleService regroupRuleService, TagGateway tagGateway) {
        this.taskRepository = taskRepository;
        this.problemSetRepository = problemSetRepository;
        this.regroupRuleRepository = regroupRuleRepository;
        this.taskService = taskService;
        this.problemService = problemService;
        this.problemSetService = problemSetService;
        this.regroupRuleService = regroupRuleService;
        this.tagGateway = tagGateway;
    }


    // region task
    public TaskVO getTask(long taskId) {
        return AppServiceUtils.getById(taskId, taskRepository::getTask,
                TaskAssembler.Instance::toTaskVO);
    }

    @HandleServiceException
    public PagedObjects<TaskVO> getTasksByQuery(@NotNull PagedQuery query) {
        var pagedObjects = taskRepository.getTasksByQuery(query);
        return AppServiceUtils.convertPagedObjects(pagedObjects, TaskAssembler.Instance::toTaskVO);
    }

    @HandleServiceException
    public Collection<TaskVO> getUncompletedTasks(@Min(0) long userId) {
        var tasks = taskService.getUncompletedTasks(userId);
        return CollectionUtils.toArrayList(tasks, TaskAssembler.Instance::toTaskVO);
    }

    @HandleServiceException
    public Collection<TaskVO> getCompletedTaskByPage(@Min(0) long userId, @Min(0) int pageNumber) {
        var tasks = taskService.getCompletedTaskByPage(userId, pageNumber);
        return CollectionUtils.toArrayList(tasks, TaskAssembler.Instance::toTaskVO);
    }

    @HandleServiceException
    public long createTaskByCollection(@NotNull CreateTaskByCollectionCommand command) {
        command.setOperatorId(getCurrentUserId());
        var set = problemSetService.createProblemSetByCollection(command.getCollectionCode(), command.getOrganizationId(), command.getOperatorId());
        if (Objects.isNull(set)) return 0;
        var userIds = new ArrayList<Long>();
        userIds.add(command.getOperatorId());
        var taskIds = taskService.createTasksBySet(set.getSetId(), userIds, command.getOperatorId());
        if (taskIds.isEmpty()) return 0;
        return taskIds.stream().findFirst().orElse(0L);
    }

    /*@HandleServiceException
    public long useExaminationCode(@Min(0) long userId, @NotBlank String examinationCode) {
        return taskService.useExaminationCode(userId, examinationCode);
    }*/

    @HandleServiceException
    public long createTaskByKnowledgePoints(@NotNull CreateTaskByKnowledgePointsCommand command) {
        command.setOperatorId(getCurrentUserId());
        var problemIds = tagGateway.getProblemIdsByKnowledgePoints(command.getPointIds());
        problemIds = RandomHelper.getRandomCollection(problemIds, command.getQuantity());
        if (problemIds.isEmpty()) return 0;
        var userIds = new ArrayList<Long>();
        userIds.add(command.getUserId());
        var set = problemSetService.createProblemSetByProblems(problemIds, command.getOperatorId(), "", "", 0, 0);
        if (Objects.isNull(set)) return 0;
        var taskIds = taskService.createTasksBySet(set.getSetId(), userIds, command.getOperatorId());
        if (taskIds.isEmpty()) return 0;
        return taskIds.stream().findFirst().orElse(0L);
    }

    @HandleServiceException
    public long createTaskByRule(@NotNull CreateTaskByRuleCommand command) {
        command.setOperatorId(getCurrentUserId());
        var rule = regroupRuleRepository.getRegroupRuleByCode(command.getRuleCode(), command.getOrganizationId());
        if (Objects.isNull(rule)) return 0;

        var set = problemSetService.createProblemSetByRule(rule.getRuleId(), command.getOperatorId());

        //var problemIds = regroupRuleService.getProblemIdsByRule(rule.getRuleId());
        var userIds = new ArrayList<Long>();
        userIds.add(command.getUserId());
        //var set = problemSetService.createProblemSetByProblems(problemIds, command.getOperatorId(), "", "", 0, 0);
        if (Objects.isNull(set)) return 0;
        var taskIds = taskService.createTasksBySet(set.getSetId(), userIds, command.getOperatorId());
        if (taskIds.isEmpty()) return 0;
        return taskIds.stream().findFirst().orElse(0L);
    }

    /*@HandleServiceException
    public long createTaskByCourseOutline(@Min(0) long courseId, @Min(0) long contentId, @Min(0) long userId) {
        return taskService.createTaskByCourseOutline(courseId, contentId, userId);
    }*/

    @HandleServiceException
    public Collection<Long> assignProblemSet(@NotNull AssignProblemSetCommand command) {
        command.setOperatorId(getCurrentUserId());
        var userIds = command.getUserIds();
        if (userIds.isEmpty()) return new ArrayList<Long>();
        return taskService.createTasksBySet(command.getSetId(), userIds, command.getOperatorId());
    }
    // endregion


    @HandleServiceException
    public Collection<ProblemVO> getProblemsByTask(@Min(0) long taskId) {
        var setId = taskService.getSetIdByTask(taskId);
        var problemIds = problemSetRepository.getProblemIdsBySet(setId);
        if (problemIds.isEmpty()) return new ArrayList<>();
        var problems = problemService.getProblemsByIds(problemIds);
        return CollectionUtils.toArrayList(problems, ProblemAssembler.Instance::toProblemVO);
    }
}
